﻿using DetectingKinectSencor._10_ColorStream;
using DetectingKinectSencor._40_Tools;
using OxyPlot;
using OxyPlot.Axes;
using OxyPlot.Series;
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media.Imaging;

namespace DetectingKinectSencor._50_Evaluation.ViewModels.DetailedEvalaution
{
    class SlidesViewModelDetailed : Notifier
    {
        // Internal variable in which the model is saved in this class
        private PlotModel plotModel;
        private PlotModel plotModelTotalAmount;
        private PlotModel plotModelSlidesPerMinute;

        private PlotModel tempPlotModelDataTime;
        private PlotModel tempPlotModelTotalAmount;
        private PlotModel tempPlotModelSlidesPerMinute;


        private LineSeries timepointSerieSlideChangeList;
        private LineSeries timepointSerieImageDetected;
        private LineSeries timepointSerieVideoDetected;
        private LineSeries timepointSerieSlideChangeListSlidesPerMinute;


        private DateTime captureTimeLastSequence;
        private int secondsForFileName;
        private int minutesForFileName;

        private List<TimeSpanAggregated> timeSpanAggregated;

        // Defines a timespan of 30 seconds
        private TimeSpan interval = new TimeSpan(0, 2, 0);

        private TimeSpan actualInterval;
        private TimeSpanAggregated timeSpan;
        private TimeSpan actualIntervalUpperBound;



        // Important the UI needs to bind the Model to SlideChangePlotModel!!!
        public PlotModel SlidesChangePlotModel
        {
            get { return plotModel; }
            set { plotModel = value; RaisePropertyChanged(() => SlidesChangePlotModel); }
        }

        public PlotModel SlidesChangePlotModelTotalAmount
        {
            get { return plotModelTotalAmount; }
            set { plotModelTotalAmount = value; RaisePropertyChanged(() => SlidesChangePlotModelTotalAmount); }
        }

        public PlotModel SlidesChangePlotModelSlidesPerMinute
        {
            get { return plotModelSlidesPerMinute; }
            set { plotModelSlidesPerMinute = value; RaisePropertyChanged(() => SlidesChangePlotModelSlidesPerMinute); }
        }

        public SlidesViewModelDetailed(DateTime lastElementCaptureTime, SnapshotManager snapshotManager)
        {
            tempPlotModelDataTime = new PlotModel();
            tempPlotModelTotalAmount = new PlotModel();
            tempPlotModelSlidesPerMinute = new PlotModel();

            SetUpModelDetailed();
            LoadDataDetailed(lastElementCaptureTime, snapshotManager);
        }



        private void SetUpModelDetailed()
        {

            // Define the legend for the date/time graph


            tempPlotModelDataTime.LegendTitle = "Legend";
            tempPlotModelDataTime.LegendOrientation = LegendOrientation.Horizontal;
            tempPlotModelDataTime.LegendPlacement = LegendPlacement.Outside;
            tempPlotModelDataTime.LegendPosition = LegendPosition.TopRight;
            tempPlotModelDataTime.LegendBackground = OxyColor.FromAColor(200, OxyColors.White);
            tempPlotModelDataTime.LegendBorder = OxyColors.Black;
            tempPlotModelDataTime.LegendFontSize = DesignOfGraphs.fontSizeDetailed;


            // Axes which shows the date when the speaker looked away
            TimeSpanAxis timeLineAxis = new TimeSpanAxis(AxisPosition.Bottom,"Timeline (mm:ss)", "mm:ss")
                                                        {
                                                            MajorGridlineStyle = LineStyle.Solid,
                                                            MinorGridlineStyle = LineStyle.Dot,
                                                            FontSize = DesignOfGraphs.fontSizeDetailed
                                                        };

            // Add the axes to the plot model
            tempPlotModelDataTime.Axes.Add(timeLineAxis);

            // Axes which shows the Amount of time the speaker stood on the same spot
            TimeSpanAxis timeSpanAxis = new TimeSpanAxis(AxisPosition.Left, "Time on slide\n(mm:ss)", "mm:ss")
                                                  {
                                                      MajorGridlineStyle = LineStyle.Solid,
                                                      MinorGridlineStyle = LineStyle.Dot,

                                                      MinorStep = (interval.TotalSeconds / 4),
                                                      MajorStep = (interval.TotalSeconds / 2),
                                                      FontSize = DesignOfGraphs.fontSizeDetailed
                                                  };

            // Add the axes to the plot model
            tempPlotModelDataTime.Axes.Add(timeSpanAxis);




            // Define the legend for the bar graph

            tempPlotModelTotalAmount.LegendTitle = "Legend";
            tempPlotModelTotalAmount.LegendOrientation = LegendOrientation.Horizontal;
            tempPlotModelTotalAmount.LegendPlacement = LegendPlacement.Outside;
            tempPlotModelTotalAmount.LegendPosition = LegendPosition.BottomCenter;
            tempPlotModelTotalAmount.LegendBackground = OxyColor.FromAColor(200, OxyColors.White);
            tempPlotModelTotalAmount.LegendBorder = OxyColors.Black;
            tempPlotModelTotalAmount.LegendFontSize = DesignOfGraphs.fontSizeDetailed;


            // Axes for the bar graph
            CategoryAxis categoryAxis = new CategoryAxis();

            //            categoryAxis.MinorStep = 1;
            categoryAxis.Labels.Add("Total Amount");
            categoryAxis.FontSize = DesignOfGraphs.fontSizeDetailed;

            tempPlotModelTotalAmount.Axes.Add(categoryAxis);
            tempPlotModelTotalAmount.LegendFontSize = DesignOfGraphs.fontSizeDetailed;


            // Define the legend for the slides per minute graph

            tempPlotModelSlidesPerMinute.LegendTitle = "Legend";
            tempPlotModelSlidesPerMinute.LegendOrientation = LegendOrientation.Horizontal;
            tempPlotModelSlidesPerMinute.LegendPlacement = LegendPlacement.Outside;
            tempPlotModelSlidesPerMinute.LegendPosition = LegendPosition.TopRight;
            tempPlotModelSlidesPerMinute.LegendBackground = OxyColor.FromAColor(200, OxyColors.White);
            tempPlotModelSlidesPerMinute.LegendBorder = OxyColors.Black;
            tempPlotModelSlidesPerMinute.LegendFontSize = DesignOfGraphs.fontSizeDetailed;

            TimeSpanAxis timeLineAxisPercentage = new TimeSpanAxis(AxisPosition.Bottom, "Timeline (mm:ss)", "mm:ss")
            {
                MajorGridlineStyle = LineStyle.Solid,
                MinorGridlineStyle = LineStyle.Dot,
                MajorStep = interval.TotalSeconds,
                Angle = -50,
                AxisTitleDistance = 12,
                FontSize = DesignOfGraphs.fontSizeDetailed
            };

            // Add the axes to the plot model
            tempPlotModelSlidesPerMinute.Axes.Add(timeLineAxisPercentage);


            LinearAxis valueAxisPercentage = new LinearAxis(AxisPosition.Left, "Slide changes\nin two minutes")
            {
                MajorGridlineStyle = LineStyle.Solid,
                MinorGridlineStyle = LineStyle.Dot,
                FontSize = DesignOfGraphs.fontSizeDetailed
            };

            // Add the axes to the plot model
            tempPlotModelSlidesPerMinute.Axes.Add(valueAxisPercentage);
        }








        public void LoadDataDetailed(DateTime captureTime, SnapshotManager snapshotManager)
        {
            // Get the list with the viewingDirectionData
            SlideChangeData slideChangeList = EvaluationData.slideChangeData;
            ImageDetectedData imageDetectedList = EvaluationData.imageDetectedData;
            VideoDetectedData videoDetectedList = EvaluationData.videoDetectedData;
            

            TimeSpan elapsedTime;

            this.captureTimeLastSequence = captureTime;




            // Defines the data time graph

            timepointSerieSlideChangeList = new LineSeries
            {
                StrokeThickness = 2,
                MarkerSize = 3,
                MarkerStroke = OxyColors.DimGray,
                MarkerType = Graph.markerTypes[1],
                CanTrackerInterpolatePoints = false,
                Title = string.Format("Slide changes"),
                Smooth = false,
            };



            // Defines the bars of total Amount graph

            ColumnSeries columnSeriesSlideChange = new ColumnSeries
            {
                LabelFormatString = "{0}",
                StrokeThickness = 1,
                FillColor = OxyColors.Green,
                Title = "Slide changes"
            };

            tempPlotModelTotalAmount.Series.Add(columnSeriesSlideChange);




            // Defines the slidesPerMinute graph

            timepointSerieSlideChangeListSlidesPerMinute = new StairStepSeries
            {
                Color = OxyColors.Blue,
                VerticalLineStyle = LineStyle.Dash,
                CanTrackerInterpolatePoints = false,
                Title = string.Format("Slide changes"),
                Smooth = false,
            };




            // Defines the image graph

            timepointSerieImageDetected = new LineSeries
            {
                StrokeThickness = 2,
                MarkerSize = 3,
                MarkerStroke = OxyColors.Tomato,
                MarkerType = Graph.markerTypes[2],
                CanTrackerInterpolatePoints = false,
                Title = string.Format("Images"),
                Smooth = false,
            };




            // Defines the video graph

            timepointSerieVideoDetected = new LineSeries
            {
                StrokeThickness = 2,
                MarkerSize = 3,
                MarkerStroke = OxyColors.PaleGreen,
                MarkerType = Graph.markerTypes[3],
                CanTrackerInterpolatePoints = false,
                Title = string.Format("Videos"),
                Smooth = false,
            };




            // Add the data points slideChange

            foreach (CaptureTime slideChange in slideChangeList.trackingSequences)
            {
                if (captureTime == slideChange.captureTime)
                {
                    timeSpanAggregated = new List<TimeSpanAggregated>();

                    // The actualInterval starts at 0 seconds
                    actualInterval = new TimeSpan(0, 0, 0);

                    // The upper bound starts at 60 seconds
                    actualIntervalUpperBound = interval;

                    // The first interval is 0-60
                    timeSpan = new TimeSpanAggregated(new TimeSpan(0, 0, 0), new TimeSpan(0, 0, 0));


                    for (int i = 0; i < slideChange.timePoints.Count; i++)
                    {
                        // It is more intuitiv to see the actual elapsed time from the beginning then the actual time 
                        elapsedTime = slideChange.timePoints[i].timePoint - captureTime;

                        timepointSerieSlideChangeList.Points.Add(new DataPoint(
                                                                               TimeSpanAxis.ToDouble(elapsedTime),
                                                                               TimeSpanAxis.ToDouble(slideChange.timePoints[i].timeSpan)));
                        
                        
                        // Add the timepoints which are in the interval to the list and calculate the percentage later
                        if (elapsedTime >= actualInterval && elapsedTime <= actualIntervalUpperBound)
                        {
                            timeSpan.totalAmount++;
                        }
                        else
                        {
                            timeSpanAggregated.Add(timeSpan);

                            // Define the lower bound of the interval
                            actualInterval += interval;

                            // Define the upper bound of the interval
                            actualIntervalUpperBound += interval;


                            // Timespan object for the new interval
                            timeSpan = new TimeSpanAggregated(actualInterval, 0);

                            // decrement the indexer that the data point is checked against the next interval
                            i--;
                        }
                    }


                    if (timeSpanAggregated.Count != 0)
                    {
                        if (!(timeSpanAggregated[timeSpanAggregated.Count - 1].Equals(timeSpan)))
                        {
                            timeSpanAggregated.Add(timeSpan);
                        }
                    }

                    TimeSpan intervalPercentage = new TimeSpan(0, 0, 0);


                    for (int i = 0; i < timeSpanAggregated.Count; i++)
                    {
                        timepointSerieSlideChangeListSlidesPerMinute.Points.Add(new DataPoint(
                                                                        TimeSpanAxis.ToDouble(intervalPercentage),
                                                                        timeSpanAggregated[i].totalAmount));

                        // When using the step graph, the peek needs to be at the starting point 0,
                        // because the first interval is 0-30. This is why the saved interval in 
                        // timeSpanAggregated[i].timespan can not be used, because then would the first 
                        // peek be at 30! and the whole graph would be moved to the right.
                        intervalPercentage += interval;
                    }


                    // Add a final point which closes the interval
                    timepointSerieSlideChangeListSlidesPerMinute.Points.Add(new DataPoint(
                                                                                TimeSpanAxis.ToDouble(intervalPercentage),
                                                                                0));

                    // Add the time point to the date/time graph
                    tempPlotModelDataTime.Series.Add(timepointSerieSlideChangeList);

                    // ad the total Amount to the bar graph
                    columnSeriesSlideChange.Items.Add(new ColumnItem(slideChange.timePoints.Count));

                    tempPlotModelSlidesPerMinute.Series.Add(timepointSerieSlideChangeListSlidesPerMinute);

                    break;
                }
            }



            // Add the data points image detected

            foreach (CaptureTime imageDetected in imageDetectedList.trackingSequences)
            {
                if (captureTime == imageDetected.captureTime)
                {

                    for (int i = 0; i < imageDetected.timePoints.Count; i++)
                    {
                        // It is more intuitiv to see the actual elapsed time from the beginning then the actual time 
                        elapsedTime = imageDetected.timePoints[i].timePoint - captureTime;

                        timepointSerieImageDetected.Points.Add(new DataPoint(
                                                                      TimeSpanAxis.ToDouble(elapsedTime),
                                                                      TimeSpanAxis.ToDouble(new TimeSpan(0,0,30))));
                    }

                    // Add the time point to the date/time graph
                    tempPlotModelDataTime.Series.Add(timepointSerieImageDetected);

                    break;
                }
            }


            // Add the data points video detected

            foreach (CaptureTime videoDetected in videoDetectedList.trackingSequences)
            {
                if (captureTime == videoDetected.captureTime)
                {
                    for (int i = 0; i < videoDetected.timePoints.Count; i++)
                    {
                        // It is more intuitiv to see the actual elapsed time from the beginning then the actual time 
                        elapsedTime = videoDetected.timePoints[i].timePoint - captureTime;
                        timepointSerieVideoDetected.Points.Add(new DataPoint(TimeSpanAxis.ToDouble(elapsedTime),
                                                                          TimeSpanAxis.ToDouble(videoDetected.timePoints[i].timeSpan)));
                    }

                    tempPlotModelDataTime.Series.Add(timepointSerieVideoDetected);
                    break;
                }
            }



            //Saved the tempPlotModel to the plotModel than is the OnPropertyChanged executed and the UI is updated
            SlidesChangePlotModel = tempPlotModelDataTime;
            SlidesChangePlotModelTotalAmount = tempPlotModelTotalAmount;
            SlidesChangePlotModelSlidesPerMinute = tempPlotModelSlidesPerMinute;
            





            // Event handler for the mous click slide change
            timepointSerieSlideChangeList.MouseDown += (s, e) =>
            {
                // only handle the left mouse button (right button can still be used to pan)
                if (e.ChangedButton == OxyMouseButton.Left)
                {
                    int indexOfNearestPoint = (int)Math.Round(e.HitTestResult.Index);

                    foreach (CaptureTime slideChange in slideChangeList.trackingSequences)
                    {
                        if (captureTimeLastSequence == slideChange.captureTime)
                        {
                            // Calculate the timePoint for the clicked point on the graph
                            double timePoint = timepointSerieSlideChangeList.Points[indexOfNearestPoint].X;

                            for (int i = 0; i < slideChange.timePoints.Count; i++)
                            {
                                // calculate the timePoint for the openGesture timePoint
                                double elapsedTimeTemp = TimeSpanAxis.ToDouble(slideChange.timePoints[i].timePoint - captureTimeLastSequence);

                                if (elapsedTimeTemp == timePoint)
                                {
                                    DateTime tempTimePoint = slideChange.timePoints[i].timePoint;

                                    minutesForFileName = tempTimePoint.Minute;
                                    secondsForFileName = tempTimePoint.Second;


                                    for (int j = 0; j <= XMLproperties.secondsTillSnapshot; j++)
                                    {

                                        string filename = "Snapshots\\" +
                                                          tempTimePoint.Day +
                                                          "_" +
                                                          tempTimePoint.Month +
                                                          "_" +
                                                          tempTimePoint.Year +
                                                          "_" +
                                                          tempTimePoint.Hour +
                                                          "_" +
                                                          minutesForFileName +
                                                          "_" +
                                                          secondsForFileName +
                                                          ".jpg";

                                        if (File.Exists(filename))
                                        {

                                            Stream imageStreamSource = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
                                            JpegBitmapDecoder decoder = new JpegBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
                                            BitmapSource bitmapSource = decoder.Frames[0];

                                            WriteableBitmap wbitmap = new WriteableBitmap(bitmapSource);

                                            snapshotManager.update(wbitmap);
                                            break;
                                        }

                                        if ((secondsForFileName) > 60)
                                        {
                                            minutesForFileName++;
                                            secondsForFileName = 0;
                                        }
                                        else
                                        {
                                            secondsForFileName++;
                                        }
                                    }
                                    break;
                                }


                            }
                            break;
                        }
                    }
                }
            };



            // Event handler for the mous click image detected
            timepointSerieImageDetected.MouseDown += (s, e) =>
            {
                // only handle the left mouse button (right button can still be used to pan)
                if (e.ChangedButton == OxyMouseButton.Left)
                {
                    int indexOfNearestPoint = (int)Math.Round(e.HitTestResult.Index);


                    //var nearestPoint = timepointSerieOpenGesturesList.Transform(timepointSerieOpenGesturesList.Points[indexOfNearestPoint]);
                    //Console.WriteLine("neares point: " + nearestPoint);


                    foreach (CaptureTime imageDetected in imageDetectedList.trackingSequences)
                    {
                        if (captureTimeLastSequence == imageDetected.captureTime)
                        {
                            // Calculate the timePoint for the clicked point on the graph
                            double timePoint = timepointSerieImageDetected.Points[indexOfNearestPoint].X;

                            for (int i = 0; i < imageDetected.timePoints.Count; i++)
                            {
                                // calculate the timePoint for the openGesture timePoint
                                double elapsedTimeTemp = TimeSpanAxis.ToDouble(imageDetected.timePoints[i].timePoint - captureTimeLastSequence);

                                if (elapsedTimeTemp == timePoint)
                                {
                                    DateTime tempTimePoint = imageDetected.timePoints[i].timePoint;

                                    minutesForFileName = tempTimePoint.Minute;
                                    secondsForFileName = tempTimePoint.Second;


                                    for (int j = 0; j <= XMLproperties.secondsTillSnapshot; j++)
                                    {

                                        string filename = "Snapshots\\" +
                                                          tempTimePoint.Day +
                                                          "_" +
                                                          tempTimePoint.Month +
                                                          "_" +
                                                          tempTimePoint.Year +
                                                          "_" +
                                                          tempTimePoint.Hour +
                                                          "_" +
                                                          minutesForFileName +
                                                          "_" +
                                                          secondsForFileName +
                                                          ".jpg";

                                        if (File.Exists(filename))
                                        {

                                            Stream imageStreamSource = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
                                            JpegBitmapDecoder decoder = new JpegBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
                                            BitmapSource bitmapSource = decoder.Frames[0];

                                            WriteableBitmap wbitmap = new WriteableBitmap(bitmapSource);

                                            snapshotManager.update(wbitmap);
                                            break;
                                        }

                                        if ((secondsForFileName) > 60)
                                        {
                                            minutesForFileName++;
                                            secondsForFileName = 0;
                                        }
                                        else
                                        {
                                            secondsForFileName++;
                                        }
                                    }
                                    break;
                                }


                            }
                            break;
                        }
                    }
                }
            };






            // Event handler for the mous click video detected
            timepointSerieVideoDetected.MouseDown += (s, e) =>
            {
                // only handle the left mouse button (right button can still be used to pan)
                if (e.ChangedButton == OxyMouseButton.Left)
                {
                    int indexOfNearestPoint = (int)Math.Round(e.HitTestResult.Index);


                    foreach (CaptureTime videoDetected in videoDetectedList.trackingSequences)
                    {
                        if (captureTimeLastSequence == videoDetected.captureTime)
                        {
                            // Calculate the timePoint for the clicked point on the graph
                            double timePoint = timepointSerieVideoDetected.Points[indexOfNearestPoint].X;

                            for (int i = 0; i < videoDetected.timePoints.Count; i++)
                            {
                                // calculate the timePoint for the openGesture timePoint
                                double elapsedTimeTemp = TimeSpanAxis.ToDouble(videoDetected.timePoints[i].timePoint - captureTimeLastSequence);

                                if (elapsedTimeTemp == timePoint)
                                {
                                    DateTime tempTimePoint = videoDetected.timePoints[i].timePoint;

                                    minutesForFileName = tempTimePoint.Minute;
                                    secondsForFileName = tempTimePoint.Second;


                                    for (int j = 0; j <= XMLproperties.secondsTillSnapshot; j++)
                                    {

                                        string filename = "Snapshots\\" +
                                                          tempTimePoint.Day +
                                                          "_" +
                                                          tempTimePoint.Month +
                                                          "_" +
                                                          tempTimePoint.Year +
                                                          "_" +
                                                          tempTimePoint.Hour +
                                                          "_" +
                                                          minutesForFileName +
                                                          "_" +
                                                          secondsForFileName +
                                                          ".jpg";

                                        if (File.Exists(filename))
                                        {

                                            Stream imageStreamSource = new FileStream(filename, FileMode.Open, FileAccess.Read, FileShare.Read);
                                            JpegBitmapDecoder decoder = new JpegBitmapDecoder(imageStreamSource, BitmapCreateOptions.PreservePixelFormat, BitmapCacheOption.Default);
                                            BitmapSource bitmapSource = decoder.Frames[0];

                                            WriteableBitmap wbitmap = new WriteableBitmap(bitmapSource);

                                            snapshotManager.update(wbitmap);
                                            break;
                                        }

                                        if ((secondsForFileName) > 60)
                                        {
                                            minutesForFileName++;
                                            secondsForFileName = 0;
                                        }
                                        else
                                        {
                                            secondsForFileName++;
                                        }
                                    }
                                    break;
                                }


                            }
                            break;
                        }
                    }
                }
            };
        }
    }
}
